﻿using System;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace Alien.NetWork
{
    public delegate void MessageHandler(MessageEventArgs e);
    public delegate void ErrorHandler(SocketException e);

    public class SocketHelper
    {
        static string host;
        static int port;
        static Socket socket;
        static SocketAsyncEventArgs socketEventArgs;

        /// <summary>
        /// 接受到数据
        /// </summary>
        public static event MessageHandler OnReceiveMessage;

        public static event ErrorHandler OnSocketError;

        /// <summary>
        /// 创建连接
        /// </summary>
        /// <param name="Host">服务端IP</param>
        /// <param name="Port">服务端口</param>
        public static void Create(string Host, int Port)
        {
            host = Host;
            port = Port;
            DnsEndPoint hostEntry = new DnsEndPoint(host, port);
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            socketEventArgs = new SocketAsyncEventArgs();
            socketEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(socketEventArgs_Completed);
            socketEventArgs.RemoteEndPoint = hostEntry;
            socketEventArgs.UserToken = socket;
        }

        static void socketEventArgs_Completed(object sender, SocketAsyncEventArgs e)
        {
            // 检查是否发送出错
            if (e.SocketError != SocketError.Success)
            {
                Exception se;
                if (e.SocketError == SocketError.ConnectionAborted)
                {
                    se = new Exception("连接超时请重试！ " + e.SocketError);
                }
                else if (e.SocketError == SocketError.ConnectionRefused)
                {
                    se = new Exception("服务器端问启动" + e.SocketError);
                }
                else
                {
                    se = new Exception("出错了" + e.SocketError);
                }

                //关闭连接清理资源
                if (e.UserToken != null)
                {
                    Socket sock = e.UserToken as Socket;
                    try
                    {
                        sock.Shutdown(SocketShutdown.Both);
                    }
                    catch (SocketException see)
                    {
                        if (OnSocketError != null)
                        {
                            OnSocketError(see);
                        }
                    }
                    finally
                    {
                        sock.Close();
                    }
                }
                throw se;
            }
            //检查Socket的当前最后的一个操作
            switch (e.LastOperation)
            {
                //如果最后的一个操作是连接，那么下一步处理就是发送消息。
                case SocketAsyncOperation.Connect:
                    if (e.UserToken != null)
                    {
                        //获取运行中的Socket对象
                        Socket sock = e.UserToken as Socket;
                        //开始发送
                        bool completesAsynchronously = sock.SendAsync(e);
                        //检查socket发送是否被挂起，如果被挂起将继续进行处理
                        if (!completesAsynchronously)
                        {
                            socketEventArgs_Completed(e.UserToken, e);
                        }
                    };
                    break;
                //如果最后的一个操作是发送，那么显示刚才发送成功的消息，然后开始下一步处理就是接收消息。
                case SocketAsyncOperation.Send:
                    //将已成功发送的消息内容绑定到listBox1控件中
                    if (e.UserToken != null)
                    {
                        //获取运行中的Socket对象
                        Socket sock = e.UserToken as Socket;
                        //开始接收服务器端的消息
                        bool completesAsynchronously = sock.ReceiveAsync(e);
                        //检查socket发送是否被挂起，如果被挂起将继续进行处理
                        if (!completesAsynchronously)
                        {
                            socketEventArgs_Completed(e.UserToken, e);
                        }
                    }
                    break;
                //如果是最后的一个操作时接收，那么显示接收到的消息内容，并清理资源。
                case SocketAsyncOperation.Receive:
                    if (e.UserToken != null)
                    {
                        //获取接收到的消息，并转化为字符串
                        string dataFromServer = Encoding.UTF8.GetString(e.Buffer, 0, e.BytesTransferred);
                        //获取运行中的Socket对象
                        Socket sock = e.UserToken as Socket;
                        //将接收到的消息内容绑定到listBox1控件中
                        if(OnReceiveMessage!=null)
                        {
                            MessageEventArgs me = new MessageEventArgs(dataFromServer);
                            OnReceiveMessage(me);
                        }
                        
                    }
                    break;
            }
        }

        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="Message">消息</param>
        public static void Send(string Message)
        {
            Message += ";";
            byte[] buffer = Encoding.UTF8.GetBytes(Message);
            socketEventArgs.SetBuffer(buffer, 0, buffer.Length);

            try
            {
                socket.ConnectAsync(socketEventArgs);
            }
            catch (SocketException se)
            {
                if (OnSocketError != null)
                {
                    OnSocketError(se);
                }
            }
        }
    }

    /// <summary>
    /// 消息事件参数
    /// </summary>
    public class MessageEventArgs
    {
        private string message;

        public string Message
        {
            get{return message;}
        }

        public MessageEventArgs(string Message)
        {
            message=Message;
        }
    }
}
